package shop.ynubeggar.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import shop.ynubeggar.enums.AuthorizationTypeEnums;
import shop.ynubeggar.exception.CustomException;
import shop.ynubeggar.interceptor.LoginInterceptor;
import shop.ynubeggar.mapper.UserMapper;
import shop.ynubeggar.model.dataobject.UserDO;
import shop.ynubeggar.model.valueobject.LoginUser;
import shop.ynubeggar.model.valueobject.UserVO;
import shop.ynubeggar.request.LoginRequest;
import shop.ynubeggar.request.RegisterRequest;
import shop.ynubeggar.request.UpdateUserInfoRequest;
import shop.ynubeggar.service.UserService;
import shop.ynubeggar.service.VerifyService;
import shop.ynubeggar.utils.CommonUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

import static shop.ynubeggar.utils.JwtParameter.*;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Resource
    VerifyService verifyService;
    @Resource
    UserMapper userMapper;

    @Override
    public UserVO findUserDetail() {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        UserDO userDO = userMapper.selectById(loginUser.getId());
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(userDO, userVO);
        return userVO;
    }

    /**
     * 用户注册
     * * 邮箱验证码验证-密码加密-账号唯一性检查-插入数据库-新注册用户福利发放
     *
     * @param captchaKey      redis存储的验证码key
     *                        verifyService。verifyCode方法将通过该key找到对应value并验证；
     * @param registerRequest 注册数据对象
     */
    @Override
    public void userRegister(String captchaKey, RegisterRequest registerRequest) {
//        仅通过图形验证码注册
        if (ObjectUtil.hasNull(registerRequest)) {
            throw new CustomException(HttpStatus.NOT_FOUND, "The registration information cannot contain empty item");
        }
        verifyService.verifyCode(captchaKey, registerRequest.getCode());
        checkUnique(registerRequest);

//        密码加密：结合hutool，使用sm3国密算法 摘要 加密  TODO 引入密码盐
        registerRequest.setPwd(DigestUtil.digester(ALGORITHM).digestHex(registerRequest.getPwd()));

        UserDO userDO = new UserDO(registerRequest);
        int res = userMapper.insert(userDO);
//        TODO 插入对象的长度校验，未来可以结合ResponseBody进行错误处理的改造
        log.info("res:{},registration success:{}", res, userDO);
        afterRegisterTask();
    }

    @Override
    public String userLogin(LoginRequest loginRequest, HttpServletRequest httpRequest) {
        List<UserDO> userDOList = userMapper.selectList(new QueryWrapper<UserDO>().eq("phone", loginRequest.getPhone()));
        if (userDOList == null || userDOList.size() != 1) {
            throw new CustomException(HttpStatus.NOT_FOUND, "The phone number is not registered");
        }
        UserDO user = userDOList.get(0);
        checkUserType(user);
        checkPassword(loginRequest, user);

        LoginUser loginUser = new LoginUser();
        BeanUtil.copyProperties(user, loginUser);

//      颁发token， 参考：https://www.hutool.cn/docs/#/jwt/JWT%E5%B7%A5%E5%85%B7-JWTUtil
        Map<String, Object> map = BeanUtil.beanToMap(loginUser);
        map.put("ip", CommonUtils.getIpAddr(httpRequest));
        map.put("expire_time", System.currentTimeMillis() + EXPIRE_TIME);
//        hutool默认将jwt.header置为null（不严谨的理解），默认将上述map的item放入Payload。
        String token = JWTUtil.createToken(map, KEY.getBytes());

        return token;
    }

    @Override
    public void updateUserDetail(UpdateUserInfoRequest updateUserInfoRequest) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();

        UserDO userDO = new UserDO(loginUser.getId(), updateUserInfoRequest);
        int res = userMapper.updateById(userDO);
        if (res == 0) {
            throw new CustomException(HttpStatus.NOT_FOUND,
                    "Update error, user is not exists");
        }
        log.info("res:{},update success:{}", res, userDO);
    }

    @Override
    public void addPoints(Integer amount) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();

        Integer oldPoints = userMapper.selectById(loginUser.getId()).getPoints();

        UserDO userDO = new UserDO().builder().id(loginUser.getId()).points(oldPoints + amount).build();

        int res = userMapper.updateById(userDO);

        log.info("res:{},update success:{}", res, userDO);
    }


    private void checkUnique(RegisterRequest registerRequest) {
//        TODO 手机号邮箱唯一性验证
        boolean phoneIsUnique = true;
        boolean mailIsUnique = true;
        if (!phoneIsUnique) {
            throw new CustomException(HttpStatus.NOT_FOUND,
                    "Email address already exists");
        }
        if (!mailIsUnique) {
            throw new CustomException(HttpStatus.NOT_FOUND,
                    "Phone number already exists");
        }
    }

    private void afterRegisterTask() {
//        TODO　新用户福利，用户完善信息等
    }

    public void checkPassword(LoginRequest loginRequest, UserDO userDO) {
//        登陆密码sm3摘要加密 TODO 引入密码盐
        String pwdOfReqAfterMd5 = DigestUtil.digester(ALGORITHM).digestHex(loginRequest.getPwd());
//        String pwdOfReqAfterMd5 = loginRequest.getPwd();
        String pwdInDb = userDO.getPwd();
        if (!StrUtil.equals(pwdInDb,pwdOfReqAfterMd5)) {
            throw new CustomException(HttpStatus.NOT_FOUND, "incorrect password");
        }
    }

    private void checkUserType(UserDO user) {
        if (user.getUserType()!= AuthorizationTypeEnums.COSTUMER.getCode()){
            throw new CustomException(HttpStatus.NOT_FOUND,"unacceptable user type, please change another account to log in");
        }
    }
}
